package com.alibaba.markovdemo.engine.stages;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import com.alibaba.markovdemo.BO.TestRespone;
import com.alibaba.markovdemo.engine.plugins.IPlugin;
import com.alibaba.markovdemo.engine.plugins.PluginFactory;
import com.alibaba.markovdemo.engine.plugins.PluginLayout;
import com.google.gson.Gson;
import org.codehaus.groovy.util.ListHashMap;

import java.util.*;


/**
 * 功能:复杂流程处理
 * 说明:可处理用例执行阶段的发送请求=>获取结果=>校验结果的复杂流程
 */
public class CompositeBaseStage extends BaseStage {


  static final String GroupNameKey = "group_name";

  static final String PARAMS = "params";

  public HashMap<String, LinkedList<BaseStage>> runningStageGroups = new HashMap<String, LinkedList<BaseStage>>();

  public HashMap<String, JSONArray> templates = new HashMap<>();

  public HashMap<String, JSONArray> expectTemplates = new HashMap<>();

  public String stageInput;

  //该变量是CompositeBaseStage阶段即使存储最新的runData
  public RunData stageRunData = new RunData();

  public JSONArray stageJsonArray;

  ListHashMap<String, List<String>> appLogList = new ListHashMap<>();

  //每组执行结果
  HashMap<String, List<RunData>> groupResultMap = new HashMap<>();


  public HashMap<String, JSONArray> getTemplates() {
    return templates;
  }

  public HashMap<String, JSONArray> getExpectTemplates() {
    return expectTemplates;
  }

  public void addSubStage() {

  }

  /**
   * 函数功能:复杂阶段,每个赋值都要在以下分阶段赋值
   *
   * @param stageParams
   */
  @Override
  public void setStageParams(Map<StageName, Object> stageParams) {
    this.stageParams = stageParams;
    //初始化caseRun的子阶段runData
    if (this.runningStageGroups.size() > 0) {
      for (String groupName : this.runningStageGroups.keySet()) {
        for (BaseStage stage : this.runningStageGroups.get(groupName)) {
          stage.setStageParams(stageParams);
        }
      }
    }
  }

  @Override
  public void setIputData(Object inputObj) {
    this.inputObj = inputObj;
  }

  /**
   * 函数功能:整合最终testRespone,判定是否通过
   *
   * @param testRespone
   * @return
   */
  @Override
  public TestRespone setTestRespone(TestRespone testRespone) {

    //获取当前阶段的log
    testRespone.getLogStage().putAll((Map<? extends StageName, ? extends ListHashMap<String, String>>) mergeResponeLog(getLogCollection()).clone());

    boolean resultFlag = true;
    //set的结果返回
    HashMap<String, List<RunData>> groupResultMapTmp = (HashMap<String, List<RunData>>) groupResultMap.clone();
    testRespone.setRunStage(groupResultMapTmp);

    //判断本次是否能通过
    for (String groupName : groupResultMapTmp.keySet()) {
      for (RunData runData : groupResultMapTmp.get(groupName)) {
        //如果判定某组data失败,则case fail
        if (runData.getResult() == 0) {
          resultFlag = false;
          break;
        }
      }
    }
    //判断校验最终是否通过
    if (resultFlag == false) {
      testRespone.setStatus(ResultStatus.ERROR);

    } else {
      testRespone.setStatus(ResultStatus.SUCCESS);
    }
    return testRespone;
  }


  /**
   * 函数功能:对所有子阶段的RunData都赋值
   *
   * @param data
   * @param index
   */
  public void setRunData(RunningDataInfo data, int index) {

    //初始化caseRun的runData
    runData.setResult(1);
    runData.setInput(data.getInput());
    runData.setExpect(data.getExpect());
    data.setCalFieldsConfig(this.runData.getCalFieldsConfig());

    //初始化caseRun的子阶段runData
    if (this.runningStageGroups.size() > 0) {
      for (String groupName : this.runningStageGroups.keySet()) {
        for (BaseStage stage : this.runningStageGroups.get(groupName)) {
          stage.getRunData().setInput(data.getInput());
          stage.getRunData().setExpect(data.getExpect());
          stage.getRunData().getParams().put("index", index);
          stage.getRunData().setCalFieldsConfig(this.runData.getCalFieldsConfig());
          stage.setGroupName(groupName);
        }
      }
    }
  }

  /**
   * 函数功能:收集caseRun阶段中每个子阶段的log
   *
   * @return
   */
  @Override
  public List<LogInfo> getLogCollection() {

    // 非简单类型stage， 有group分组的sub stage
    if (this.runningStageGroups.size() > 0) {
      //添加所有的log
      for (String groupName : this.runningStageGroups.keySet()) {
        for (BaseStage stage : this.runningStageGroups.get(groupName)) {
          logCollection.addAll(stage.getLogCollection());
        }
      }
    } else {
      logCollection.addAll(super.getLogCollection());
    }

    return logCollection;
  }

  /**
   * 函数功能:对阶段性RunData进行赋值
   *
   * @param runData
   */
  public void setStageRunData(RunData runData) {


    if (runData.getInput() != null) {
      stageRunData.setInput(runData.getInput());
    }
    if (runData.getOutput() != null) {
      stageRunData.setOutput(runData.getOutput());
    }
    if (runData.getActual() != null) {
      stageRunData.setActual(runData.getActual());
    }

    stageRunData.setResult(runData.getResult());

    if (runData.getExpect() != null) {
      stageRunData.setExpect(runData.getExpect());
    }
    if (runData.getLog() != null) {
      stageRunData.setLog(runData.getLog());
    }
    if (runData.getParams() != null) {
      stageRunData.setParams(runData.getParams());
    }

  }


  /**
   * 函数功能:执行send=>get=>check的用例执行阶段
   */
  @Override
  public void exec() {

    LinkedHashMap<String, LinkedList<RunningDataInfo>> inputMap = (LinkedHashMap<String, LinkedList<RunningDataInfo>>) this.inputObj;
    RunData runCheckData = new RunData();

    //执行
    for (String groupName : inputMap.keySet()) {
      List<RunData> runCheckDataList = new ArrayList<>();
      int dataListIndex = 1;
      //每组中有多组input/expect
      for (RunningDataInfo runData : inputMap.get(groupName)) {
        //将输入期望传入
        setRunData(runData, dataListIndex);
        //执行run流程,这会带出所有的log和结果
        //设置初始输入
        stageInput = runData.getInput();
        //内部阶段输入
        String innerInput = runData.getInput();

        if (this.runningStageGroups.containsKey(groupName)) {
          // 依次执行send->get->check三个阶段
          for (BaseStage stage : this.runningStageGroups.get(groupName)) {
            //每个阶段的输出作为下个阶段的输入
            stage.getRunData().setInput(innerInput);
            //加这行的原因是,当某个阶段跳过时,默认输入输出是一样的
            stage.getRunData().setOutput(innerInput);
            stage.getRunData().setCalFieldsConfig(runData.getCalFieldsConfig());
            stage.getRunData().setScenarioId(runData.getScenarioId());
            stage.getRunData().setTestcaseId(runData.getTestcaseId());
            stage.exec();
            //获取当前最新的RunData
            setStageRunData(stage.getRunData());

            //获取group执行完的checkresult
            if (StageName.checkStage.equals(stage.getName())) {
              RunData stageRunDataNew = new RunData();
              stageRunDataNew.setActual(stageRunData.getActual());
              stageRunDataNew.setExpect(stageRunData.getExpect());
              stageRunDataNew.setLog(stageRunData.getLog());
              stageRunDataNew.setInput(stageInput);
              stageRunDataNew.setResult(stageRunData.getResult());
              stageRunDataNew.setParams(stageRunData.getParams());
              stageRunDataNew.setOutput(stageRunData.getOutput());
              //判断checkList中是否有插件异常
              if (stage.getRunDataList().size() > 0) {
                for (RunData runDatatmp : stage.getRunDataList()) {
                  if (runDatatmp.getResult() == 0) {
                    stageRunDataNew.setResult(0);
                    break;
                  }
                }
              }
              runCheckDataList.add(stageRunDataNew);
            }
            //如果当前阶段无plugin,则input取再上个阶段的input
            if (stage.getRunData().getOutput() != null) {
              innerInput = stage.getRunData().getOutput();
            }
          }
          if (runCheckDataList.size() > 0) {
            groupResultMap.put(groupName, runCheckDataList);
          }
          dataListIndex++;
        }
      }
    }
  }


  /**
   * 函数功能:获取check阶段的所有runData
   *
   * @return
   */
  public RunData getResult() {

    Gson gosn = new Gson();
    RunData runData = new RunData();
    List<RunData> runDataList = null;
    // 非简单类型stage， 有group分组的sub stage
    if (this.runningStageGroups.size() > 0) {
      runDataList = new ArrayList<>();
      for (String groupName : this.runningStageGroups.keySet()) {

        for (BaseStage stage : this.runningStageGroups.get(groupName)) {
          //获取实际返回的结果
          if (StageName.getResponseStage.equals(stage.getName())) {
            //拿到获取结果阶段的最终输出
            runData.setActual(stage.getRunData().getOutput());
          }
          //获取check的结果
          if (StageName.checkStage.equals(stage.getName())) {
            runData.setResult(stage.getRunData().getResult());
            runData.setOutput(stage.getRunData().getOutput());

          }
        }
      }
    }
    return runData;
  }


  /**
   * 函数功能:用例执行流程初始化
   *
   * @param stageName
   * @param stageJson
   * @return
   */
  @Override
  public BaseStage build(StageName stageName, JSONObject stageJson) {

    this.name = stageName;

    stageJsonObj = stageJson;

    //1.初始化exec中的send,get,check的3个子阶段
    if (stageJson.containsKey(ExecKey)) {
      this.stageJsonArray = (JSONArray) stageJson.get(ExecKey);
      //遍历每组
      for (Object obj : stageJsonArray) {
        JSONObject jsObj = (JSONObject) obj;
        String groupName = jsObj.getString(GroupNameKey);
        JSONArray stageList = (JSONArray) jsObj.get(ExecKey);
        LinkedList<BaseStage> baseStageList = new LinkedList<BaseStage>();
        for (Object stageObj : stageList) {
          JSONObject stageJsonObj = (JSONObject) stageObj;
          stageJsonObj.put("params", stageJson.get("params"));
          String stagename = (String) stageJsonObj.get("stageName");
          BaseStage bs = RunningStageFactory.getRunningStage(stagename, stageJsonObj);
          baseStageList.add(bs);
        }
        this.runningStageGroups.put(groupName, baseStageList);

        //templates
        JSONArray templateData = new JSONArray();
        if (jsObj.containsKey("templates")) {
          templateData = jsObj.getJSONArray("templates");
        }
        this.templates.put(groupName, templateData);

        JSONArray expectTemplateData = new JSONArray();
        if (jsObj.containsKey("expectTemplates")) {
          expectTemplateData = jsObj.getJSONArray("expectTemplates");
        }
        this.expectTemplates.put(groupName, expectTemplateData);
      }
    }

    //2.初始化before_exec和after_exec中的插件
    String[] execList = {BeforeExecKey, AfterExecKey};
    for (String execName : execList) {
      pluginList = new LinkedList<>();
      if (stageJson.containsKey(execName) && stageJson.get(execName) instanceof JSONObject) {
        JSONObject stageExecJson = (JSONObject) stageJson.get(execName);
        if (stageExecJson.containsKey("pluginList")) {
          for (Object obj : stageExecJson.getJSONArray("pluginList")) {
            JSONObject jsObj = (JSONObject) obj;
            String pluginName = (String) jsObj.get("plugin_name");
            if (!pluginNameMap.containsKey(pluginName)) {
              IPlugin plugin = PluginFactory.getPlugin(jsObj, stageJson);
              pluginNameMap.put(pluginName, plugin);
            }
            //插件
            this.addPlugin(jsObj);
          }
        }
      }
      this.pluginMap.put(execName, pluginList);
    }

    //3.初始化待收集的logList
    if (stageJson.containsKey("params")) {
      JSONObject paramsObj = (JSONObject) stageJson.get("params");
      if (paramsObj.containsKey("logFile")) {
        for (Object obj : (JSONArray) paramsObj.get("logFile")) {
          JSONObject jsObj = (JSONObject) obj;
          if (jsObj.containsKey("role") && jsObj.containsKey("log_files")) {
            String module = (String) jsObj.get("role");
            List<String> fileList = (List<String>) jsObj.get("log_files");
            if (fileList.size() > 0) {
              appLogList.put(module, fileList);
            }
          }
        }
      }
    }
    return this;
  }


  /**
   * 函数功能:标准化PluginLayout
   *
   * @param pluginList
   * @return
   */
  public List<PluginLayout> getPluginListLayout(LinkedList<JSONObject> pluginList) {

    List<PluginLayout> pluginLayoutList = new LinkedList<>();
    if (pluginList.size() > 0) {
      for (JSONObject pluginJson : pluginList) {
        PluginLayout pluginLayout = new PluginLayout();
        pluginLayout.setPluginType(pluginJson.containsKey(PLUGIN_TYPE_KEY) ? (String) pluginJson.get(PLUGIN_TYPE_KEY) : "");
        pluginLayout.setDisplayName(pluginJson.containsKey(DISPLAY_NAME_KEY) ? (String) pluginJson.get(DISPLAY_NAME_KEY) : "");
        pluginLayout.setPluginName(pluginJson.containsKey(PLUGIN_NAME_KEY) ? (String) pluginJson.get(PLUGIN_NAME_KEY) : "");
        pluginLayoutList.add(pluginLayout);
      }
    }
    return pluginLayoutList;
  }

  /**
   * 函数功能:pipeline阶段的布局json
   *
   * @return
   */
  public List<Map<Object, Object>> buildPipelineLayout() {

    Map<Object, Object> compositeLayout = new LinkedHashMap<>();
    List<Map<Object, Object>> compositeLayoutList = new ArrayList<>();

    //载入before阶段
    LinkedList<JSONObject> pluginList = pluginMap.get(BeforeExecKey);
    List<Map<Object, Object>> runLayoutList = new ArrayList<>();
    compositeLayout.put("beforeStage", getPluginListLayout(pluginList));
    compositeLayoutList.add(compositeLayout);

    //载入exec阶段
    Map<Object, Object> composite = new LinkedHashMap<>();
    compositeLayout = new LinkedHashMap<>();
    for (Object obj : stageJsonArray) {
      JSONObject jsObj = (JSONObject) obj;
      //group_name是否为必须的，这里假设为必须的
      String groupName = jsObj.getString(GroupNameKey);
      composite.put("group_name", groupName);
      JSONArray execJsObj = (JSONArray) jsObj.get("exec");

      for (Object stageObj : execJsObj) {
        JSONObject stageJsObj = (JSONObject) stageObj;
        BaseStage bs = RunningStageFactory.getRunningStage((String) stageJsObj.get("stageName"), stageJsObj);
        composite.put(bs.getName(), bs.buildLayout());
      }
      runLayoutList.add(composite);
    }
    compositeLayout.put("execStage", runLayoutList);
    compositeLayoutList.add(compositeLayout);

    //载入after阶段
    compositeLayout = new LinkedHashMap<>();
    compositeLayout.put("afterStage", getPluginListLayout(pluginMap.get(AfterExecKey)));
    compositeLayoutList.add(compositeLayout);

    return compositeLayoutList;
  }


  /**
   * 函数功能:CaseRunLayout的布局json
   *
   * @return
   */
  public List<Map<String, String>> buildCaseRunLayout() {

    List<Map<String, String>> caseRunLayoutList = new ArrayList<>();
    Map<String, String> composite = new LinkedHashMap<>();
    for (Object obj : stageJsonArray) {
      JSONObject jsObj = (JSONObject) obj;
      //group_name是否为必须的，这里假设为必须的
      String groupName = jsObj.getString(GroupNameKey);
      composite.put("group_name", groupName);
      caseRunLayoutList.add(composite);
    }

    return caseRunLayoutList;
  }


  public static String getGroupNameKey() {
    return GroupNameKey;
  }

  public HashMap<String, LinkedList<BaseStage>> getRunningStageGroups() {
    return runningStageGroups;
  }

  public void setRunningStageGroups(
      HashMap<String, LinkedList<BaseStage>> runStageGroups) {
    runningStageGroups = runStageGroups;
  }


  /**
   * 函数功能:日志收集和标准化
   *
   * @param data
   * @param stageName
   * @return
   */
  @Override
  public String logFormat(RunData data, StageName stageName) {

    String showLog = "";

    //check阶段
    if (stageName.equals(StageName.checkStage)) {

      showLog += "======================[INPUT]======================\n";
      showLog += "======================[OUTPUT]======================\n";


      showLog += "======================[EXPECT]======================\n";
      showLog += data.getExpect() + "\n";

      showLog += "======================[RESULT]======================\n";
      showLog += data.getResult() + "\n";
    }
    //appLog
    else if (stageName.equals((StageName.caseRunStage))) {

      showLog += "======================[LOG]======================\n";
      showLog += data.getLog() + "\n";
    }
    //send,respone阶段
    else {
      showLog += "======================[INPUT]======================\n";

      showLog += "======================[OUTPUT]======================\n";

    }
    return showLog;
  }


  /**
   * 函数功能:整合当前阶段所有的log,以map的格式返回,传递给testRespone
   *
   * @param logCollection
   * @return
   */
  @Override
  public HashMap<StageName, ListHashMap<String, String>> mergeResponeLog(List<LogInfo> logCollection) {

    StageName stageName;
    String pluginName;
    int dataListIndex;
    String log;
    HashMap<StageName, ListHashMap<String, String>> allLogCollection = new HashMap<>();
    ListHashMap<String, String> logList;
    String key;

    if (logCollection.size() > 0) {

      for (LogInfo logInfo : logCollection) {

        stageName = logInfo.getStageName();

        if (!allLogCollection.containsKey(stageName)) {
          logList = new ListHashMap<>();
          allLogCollection.put(stageName, logList);
        } else {
          logList = allLogCollection.get(stageName);
        }

        pluginName = logInfo.getPluginName();

        //如果是收集插件,特征是params参数带有appLogs
        if (logInfo.getRunData().getParams().containsKey("appLogs")) {
          Map<String, String> appLogs = (Map<String, String>) logInfo.getRunData().getParams().get("appLogs");
          for (String module : appLogs.keySet()) {
            log = appLogs.get(module);
            logList.put(module, log);
          }
        }
        //如果是执行类插件,特征是params参数中带有index
        if (logInfo.getRunData().getParams().containsKey("index")) {
          dataListIndex = (int) logInfo.getRunData().getParams().get("index");
          log = logInfo.getLog();
          key = pluginName + "." + dataListIndex;
          if (logInfo.getGroupName() != null) {
            key += "." + logInfo.getGroupName();
          }
          logList.put(key, log);
        }
      }
    }

    return allLogCollection;
  }


}

